﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "GroupElementChangeHandler.h"
#include "IDocument.h"
#include "IElement.h"
#include "IElementsChangeEventArgs.h"
#include "IElementsChangeEvent.h"
#include "IGroup.h"
#include "GbmpGroupUtils.h"
#include "GbmpGroupManager.h"
#include "IEditMode.h"
#include "IGroupType.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;


GroupElementChangeHandler::GroupElementChangeHandler(const ElementId& editingGroupId)
    : m_editingGroupId(editingGroupId)
    , m_isKeepListening(true)
{
}

GroupElementChangeHandler::~GroupElementChangeHandler()
{
}

void GroupElementChangeHandler::On(IElementsChangeEventArgs* pArgs)
{
    if (!m_isKeepListening)
        return;

    if (pArgs == nullptr)
        return;

    const IElementsChangeEvent* pEvent = quick_cast<IElementsChangeEvent>(pArgs->GetEvent());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pEvent, L"pEvent为空",L"GDMPLab",L"2024-03-30");

    IDocument* pDoc = pEvent->GetSender();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    std::vector<const IElement*> pElements = pArgs->GetElements();
    if (pElements.empty())
        return;

    IGroup* pEditingGroup = quick_cast<IGroup>(pDoc->GetElement(m_editingGroupId));
    if (pEditingGroup == nullptr)
        return;

    IGroup* pParentGroup = nullptr;
    if (pEditingGroup->GetGroupId().IsValid())
    {
        pParentGroup = quick_cast<IGroup>(pDoc->GetElement(pEditingGroup->GetGroupId()));
    }

    UnorderedElementIdSet editingGroupElementIds;
    pEditingGroup->GetAllElementIdsInGroup(editingGroupElementIds);
    for (const auto& pElement : pElements)
    {
        if (pElement == nullptr)
            continue;

        ElementId elementId = pElement->GetElementId();
        if (ElementsChangeEventType::ElementsAdditionEvent == pEvent->GetElementsChangeEventType())
        {
            IEditMode* pEditMode = IEditMode::GetTopActiveEditMode(pDoc);
            DBG_WARN_AND_RETURN_VOID_UNLESS(pEditMode, L"pEditMode为空",L"GDMPLab",L"2024-03-30");
            if (pEditMode->GetEditingElementId() != m_editingGroupId)
                return;

            if (GbmpGroupUtils::IsAllowedElement(pEditingGroup, pElement) && editingGroupElementIds.find(elementId) == editingGroupElementIds.end())
            {
                pEditingGroup->AddElement(elementId);
            }
        }
        else if (ElementsChangeEventType::ElementsPostUpdationEvent == pEvent->GetElementsChangeEventType())
        {
            if (editingGroupElementIds.find(elementId) != editingGroupElementIds.end())
            {
                if(pParentGroup && pParentGroup->IsReferenceElementInGroup(elementId))
                    pParentGroup->ChangeElement(elementId);
                else if (GroupManager::GetInstance(pDoc).IsSync(m_editingGroupId, elementId))
                    pEditingGroup->ChangeElement(elementId);
            }
        }
        else if (ElementsChangeEventType::ElementsPreDeletionEvent == pEvent->GetElementsChangeEventType())
        {
            if (pEditingGroup->IsElementInGroup(elementId))
            {
                if (pParentGroup && pParentGroup->IsReferenceElementInGroup(elementId))
                    pParentGroup->DeleteElement(elementId);
                else if (GroupManager::GetInstance(pDoc).IsSync(m_editingGroupId, elementId))
                    pEditingGroup->DeleteElement(elementId);
            }            
        }
    }
}


GroupTypeElementChangeHandler::GroupTypeElementChangeHandler(const ElementId& editingGroupId)
{
    m_editingGroupTypeId = editingGroupId;
}

GroupTypeElementChangeHandler::~GroupTypeElementChangeHandler()
{
}

void GroupTypeElementChangeHandler::On(IElementsChangeEventArgs* pArgs)
{
    if (pArgs == nullptr)
        return;

    const IElementsChangeEvent* pEvent = quick_cast<IElementsChangeEvent>(pArgs->GetEvent());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pEvent, L"pEvent为空",L"GDMPLab",L"2024-03-30");

    IDocument* pDoc = pEvent->GetSender();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    std::vector<const IElement*> pElements = pArgs->GetElements();
    if (pElements.empty())
        return;

    IGroupType* pEditingGroupType = quick_cast<IGroupType>(pDoc->GetElement(m_editingGroupTypeId));
    if (pEditingGroupType == nullptr)
        return;

    for (const auto& pElement : pElements)
    {
        if (!pElement || pElement->GetGroupId() != m_editingGroupTypeId)
        {
            continue;
        }
        if (ElementsChangeEventType::ElementsPreDeletionEvent == pEvent->GetElementsChangeEventType())
        {
            pEditingGroupType->DeleteElement(pElement->GetElementId());
        }
        else if (ElementsChangeEventType::ElementsPostUpdationEvent == pEvent->GetElementsChangeEventType())
        {
            pEditingGroupType->ChangeElement(pElement->GetElementId());
        }
    }
}
